﻿using FluentScheduler;
using Model;
using Model.Modules;
using Nest;
using Newtonsoft.Json;
using Proxy;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Model;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Threading;
using Utility;
using ViewModel.VM.Control;

namespace ViewModel
{
    public class VM_PageHistory : BaseViewModel
    {

        #region 变量
        public static surfacedetectEntities surfaceEntities;

        public DateTime Start { get { return start; } set { start = value; OnPropertyChanged(); } }
        private DateTime start;
        public DateTime End { get { return end; } set { end = value; OnPropertyChanged(); } }
        private DateTime end;

        public int CurrentImageType
        {
            get { return currentImageType; }
            set
            {
                currentImageType = value;
                OnPropertyChanged();
                new DefectDataHelper().setCurrentImageByImageType(SteelDefectlist, CurrentImageType);
                if (CurrentImg == null)
                    return;
                new DefectDataHelper().setCurrentImageByImageType(new List<Imagedefectinfo>() { CurrentImg }, CurrentImageType);
                var tempimg = CurrentImg;
                CurrentImg = null;
                CurrentImg = tempimg;
            }
        }
        private int currentImageType;


        public ObservableCollection<image> Imagelist { get { return imagelist; } set { imagelist = value; OnPropertyChanged(); } }
        private ObservableCollection<image> imagelist;

        public ObservableCollection<image_defect> Defectlist { get { return defectlist; } set { defectlist = value; OnPropertyChanged(); } }
        private ObservableCollection<image_defect> defectlist;

        public ObservableCollection<Imagedefectinfo> ImageDefectlist { get { return imagedefectlist; } set { imagedefectlist = value; OnPropertyChanged(); } }
        private ObservableCollection<Imagedefectinfo> imagedefectlist;

        public ObservableCollection<steeldefectinfo> SteelDefectlist { get { return steeldefectlist; } set { steeldefectlist = value; OnPropertyChanged(); } }
        private ObservableCollection<steeldefectinfo> steeldefectlist;

        public ObservableCollection<ObservableCollection<steel_defect>> SteelDefects { get { return steeldefects; } set { steeldefects = value; OnPropertyChanged(); } }
        private ObservableCollection<ObservableCollection<steel_defect>> steeldefects;
        public ObservableCollection<steel_defect> ShownSteelDefects { get { return shownsteeldefects; } set { shownsteeldefects = value; OnPropertyChanged(); } }
        private ObservableCollection<steel_defect> shownsteeldefects;

        public ObservableCollection<Imagedefectinfo> CurrentImageList { get { return currentImageList; } set { currentImageList = value; OnPropertyChanged(); } }
        private ObservableCollection<Imagedefectinfo> currentImageList;

        public int IgnoreCount { get { return ignoreCount; } set { ignoreCount = value; OnPropertyChanged(); } }
        private int ignoreCount;
        public int WarningCount { get { return warningCount; } set { warningCount = value; OnPropertyChanged(); } }
        private int warningCount;
        public int AlertCount { get { return alertCount; } set { alertCount = value; OnPropertyChanged(); } }
        private int alertCount;

        public ObservableCollection<batch> Batchlist { get { return batchlist; } set { batchlist = value; OnPropertyChanged(); } }
        private ObservableCollection<batch> batchlist;
        public ObservableCollection<BatchSumItem> BatchSumList { get { return batchSumList; } set { batchSumList = value; OnPropertyChanged(); } }
        private ObservableCollection<BatchSumItem> batchSumList;

        public ObservableCollection<steel_defect_amout> Steeldefectamout { get; set; }
        public string SearchString { get; set; }
        

        public bool IsFree { get { return isFree; } set { isFree = value; OnPropertyChanged(); } }
        private bool isFree;
        public bool IsAdmin { get { return StaticData.IsAdmin; } }


        List<DispatcherOperation> Currentoptions = new List<DispatcherOperation>();
        Task QueryTask;
        public batch CurrentBatch
        {
            get { return currentBatch; }
            set
            {

                currentBatch = value;
                OnPropertyChanged();
                if (isInit)
                {
                    UpdateDatabaseOperation();
                }

            }
        }
        private async void UpdateDatabaseOperation()
        {

            if (sourcestack.Count > 0)
            {
                sourcestack.Pop().Cancel();
            }
            if (QueryTask == null)
                QueryTask = QueryImage();
            else
            {
                Stopwatch sw = Stopwatch.StartNew();
                await QueryTask;
                sw.Stop();
                Console.WriteLine(sw.ElapsedMilliseconds);
                QueryTask = QueryImage();
            }

        }
        private batch currentBatch;
        public string Message { get { return message; } set { message = value; OnPropertyChanged(); } }
        private string message;

        public bool SteelSourceLoading { get { return steelSourceLoading; } set { steelSourceLoading = value; OnPropertyChanged(); } }
        private bool steelSourceLoading;


        public int CurrentImageIndex
        {
            get { return currentImageIndex; }
            set
            {
                currentImageIndex = value;
                OnPropertyChanged();
                //imagesFactory.UpdateImage(CurrentImageIndex);
            }
        }
        private int currentImageIndex;


        public Imagedefectinfo CurrentImg
        {
            get { return currentImg; }
            set
            {
                currentImg = value; OnPropertyChanged();
            }
        }
        private Imagedefectinfo currentImg;


        public image_defect CurrentDefect
        {
            get { return currentDefect; }
            set
            {
                currentDefect = value; OnPropertyChanged();
            }
        }
        private image_defect currentDefect;

        public steel_defect CurrentSteelDefect
        {
            get { return currentSteelDefect; }
            set
            {
                currentSteelDefect = value; OnPropertyChanged();
                updateCurrentImage();
            }
        }
        private steel_defect currentSteelDefect;
        private string gotoSteelDefectID = "";


        ESDataHelper eshelper;
        ImagesVirtualFactory imagesFactory;
        bool isInit = false;
        TestEntitity testEntitity;
        #endregion
        //CancellationTokenSource source = new CancellationTokenSource();
        Stack<CancellationTokenSource> sourcestack = new Stack<CancellationTokenSource>();
        bool hasqueryotherpage = false;
        public VM_PageHistory()
        {
            InitData();
            QueryTask = QueryImage();

        }

        private void InitData()
        {
            IsFree = true;
            SteelDefectlist = new ObservableCollection<steeldefectinfo>();
            SteelDefects = new ObservableCollection<ObservableCollection<steel_defect>>();
            ShownSteelDefects = new ObservableRangeCollection<steel_defect>();
            Steeldefectamout = new ObservableCollection<steel_defect_amout>();
            SteelDefects.CollectionChanged += (s, e) =>
            {
                switch (e.Action)
                {
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                        var addedsteel_defects = e.NewItems[0] as ObservableCollection<steel_defect>;
                        var filtered_defects = SteelDefectFilterHelper.GetFilteredSteelDefects(addedsteel_defects, StaticData.CurrentDefectFilter);
                        ShownSteelDefects = new ObservableCollection<steel_defect>(AfterAddRange<steel_defect>(ShownSteelDefects, filtered_defects).OrderByDescending(t => t.grade, new AlertTypeComparer()).ThenByDescending(t => t.repeat_id).ThenBy(t => t.type).ThenBy(t => t.real_y));
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                        ShownSteelDefects.Clear();
                        break;
                }
            };
            var startdate = DateTime.Now.AddDays(-10);
            Start = startdate;
            End = DateTime.Now;
            CurrentImageType = 1;
            eshelper = new ESDataHelper();
            surfaceEntities = new surfacedetectEntities();
            Logger.Info("SuccessInitHistoryData");
            isInit = true;
            Task.Run(() =>
            {
                QueryBatchList();
            });
            StaticData.StaticPropertyChanged += (sender, e) =>
            {
                OnPropertyChanged(nameof(IsAdmin));
            };
            JobManager.Initialize();
            JobManager.AddJob(() =>
            {
                _ = updateCurrentBatch();
            }, s => s.ToRunEvery(10).Seconds());
            JobManager.Start();
        }
        public void FilterView()
        {
            ShownSteelDefects.Clear();
            var filtered_defects = SteelDefectFilterHelper.GetFilteredSteelDefects(SteelDefects, StaticData.CurrentDefectFilter);
            ShownSteelDefects = new ObservableCollection<steel_defect>(AfterAddRange<steel_defect>(ShownSteelDefects, filtered_defects).OrderByDescending(t => t.grade, new AlertTypeComparer()).ThenByDescending(t => t.repeat_id).ThenBy(t => t.type).ThenBy(t => t.real_y));
        }
        private async Task QueryImage()
        {
            if (CurrentBatch != null)
            {
                Steeldefectamout = new ObservableCollection<steel_defect_amout>(surfaceEntities.steel_defect_amout.AsNoTracking().Where(t => t.main_id == CurrentBatch.main_id));
                IsFree = false;
                //QueryImageInfo();
                if (StaticData.DataBase == DataFrom.Test) StaticData.TestEntitity = new TestEntitity(CurrentBatch.main_id);
                var newsource = new CancellationTokenSource();
                sourcestack.Push(newsource);
                var token = newsource.Token;
                _ = QuerySteelDefects(token);
                //await QueryFirstPageSteelDefectList(token);
                IsFree = true;
            }
        }

        private async Task QuerySteelDefects(CancellationToken token)
        {
            SteelDefects.Clear();
            ImageDefectlist = new ObservableCollection<Imagedefectinfo>();
            await Task.Run(async () =>
            {

                Stopwatch sw = Stopwatch.StartNew();
                var size = 8000;
                var count = size;
                DateTime? firstinserttime = null;
                while (count == size)
                {

                    var list = await new ESDataHelper().GetSteelDefectsByMainID(CurrentBatch.main_id, false, size, firstinserttime);
                    Logger.Debug($"查询到{list.Count}条钢材缺陷数据");
                    if (!list.Any())
                        break;
                    //Diff 永钢、兴橙、南南铝历史查询需要过程掉冗余存储的钢材缺陷
                    SteelDefects.Add(new ObservableCollection<steel_defect>(list.Where(t => t.grade != "冗余存储")));
                    firstinserttime = list.Max(m => m.insert_time);
                    count = list.Count();

                }
                //给缺陷报警消息跳转对应批次对应缺陷加的逻辑
                if (gotoSteelDefectID != "")
                {

                    await Task.Run(new Action(async () =>
                    {
                        var tempgotoSteelDefectID = gotoSteelDefectID;
                        DoMenthodByDispatcher(() =>
                        {
                            gotoSteelDefectID = "";
                        });
                        await Task.Delay(100);
                        DateTime startTime = DateTime.Now;
                        steel_defect steeldefect = null;
                        while ((DateTime.Now - startTime).TotalSeconds < 2 && steeldefect == null)
                        {
                            steeldefect = ShownSteelDefects.Where(d => d.id == tempgotoSteelDefectID).FirstOrDefault();
                            // 每50毫秒执行一次
                            await Task.Delay(100);
                        }
                        startTime = DateTime.Now;
                        while ((DateTime.Now - startTime).TotalSeconds < 2 && SteelSourceLoading)
                        {
                            await Task.Delay(100);
                        }
                        if (steeldefect != null)
                        {
                            DoMenthodByDispatcher(() =>
                            {
                                CurrentSteelDefect = steeldefect;
                            });
                        }

                    }));


                }
                if (token.IsCancellationRequested)
                {
                    _ = Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        //SteelDefects.Clear();
                    }));
                }
                sw.Stop();
                Logger.Debug($"终于查询完了，用时{sw.ElapsedMilliseconds}");

            }, token);
        }

        private void updateCurrentImage()
        {
            if (SteelSourceLoading)
                CurrentSteelDefect = null;
            CurrentImg = null;
            if (CurrentSteelDefect == null)
                return;
            Task.Run(async () =>
            {
                var steelinfo = await new DefectDataHelper().getSteelDefectInfo(CurrentSteelDefect);
                Logger.Debug(steelinfo.Steel_defect.id+"--"+steelinfo.Imagedefectinfos.Count().ToString());
                if (steelinfo.Imagedefectinfos.Any())
                {
                    new DefectDataHelper().setCurrentImageByImageType(steelinfo.Imagedefectinfos, CurrentImageType);
                    DoMenthodByDispatcher(() =>
                    {
                        steelinfo.Imagedefectinfos.All(imageinfo => { imageinfo.ImageStatus = ImageInfoHelper.GetImageStatus(CurrentBatch.img_status); return true; });
                        ImageDefectlist = steelinfo.Imagedefectinfos;
                        CurrentImg = steelinfo.Imagedefectinfos[0];


                        //Logger.Debug($"当前图像缺陷对应imageid{CurrentImg.Image.id},imageurl={CurrentImg.Image.image_url}");
                    });
                }
                else
                {
                    Logger.Info($"Warning:钢材缺陷{steelinfo.Steel_defect.id}没有找到任何图像缺陷,请检查数据");
                }
            });

        }

        private async Task updateCurrentBatch()
        {
            //当此前为评估中的批次完成评估后，更新当前批次的缺陷显示
            if (CurrentBatch == null||CurrentBatch.finished==true)
                return;
            
            await Task.Run(() =>
            {
                var batch = new surfacedetectEntities().batch.AsNoTracking().Where(t => t.main_id == CurrentBatch.main_id).FirstOrDefault();
                if (batch != null&&batch.finished==true)
                {
                    DoMenthodByDispatcher(() =>
                    {
                        CurrentBatch = null;
                        CurrentBatch = batch;
                    });
                }
            });

        }
        private void CalcAlertCount(int total)
        {
            var r = new Random();
            var r1 = r.NextDouble();
            var r2 = r.NextDouble();
            var r3 = r.NextDouble();
            var sum = r1 + r2 + r3;
            IgnoreCount = (int)(total * r1 / sum);
            WarningCount = (int)(total * r2 / sum);
            AlertCount = (int)(total * r3 / sum);

        }

        public BaseCommand SearchCommand { get => new BaseCommand(SearchCommand_Executed); }
        public void SearchCommand_Executed(object obj)
        {
            QueryImage();
        }

        public BaseCommand SearchBatchCommand { get => new BaseCommand(SearchBatchCommand_Executed); }
        public void SearchBatchCommand_Executed(object obj)
        {
            QueryBatchList();
        }
        public BaseCommand SearchSingleBatchCommand{ get => new BaseCommand((obj) => {
            var batchid = obj as string;
            var batches = surfaceEntities.batch.Where(t => t.main_id== batchid||t.user_custom_id== batchid).ToList();
            if (batches.Any())
                CurrentBatch = batches[0];
            else
                MessageBox("未找到对应批次，请输入正确的批次号");
        }); }
        

        private void QueryBatchList()
        {
            //查询逻辑：
            //1.SearchString不为空时，按照SearchString查询所有批次,SearchString模糊匹配user_custom_id和user_custom_rolled_id
            //2.SearchString为空时，按照时间范围查询所有批次
            ObservableCollection<batch> batches = null;
            if (SearchString!=null&&!string.IsNullOrEmpty(SearchString.Trim()))
                batches = new ObservableCollection<batch>(surfaceEntities.batch.AsNoTracking().Where(t =>t.user_custom_id.Contains(SearchString.Trim())).OrderByDescending(o => o.insert_time).ToList());
            else
                batches = new ObservableCollection<batch>(surfaceEntities.batch.AsNoTracking().Where(t => t.insert_time >= Start && t.insert_time <= End).OrderByDescending(o => o.insert_time).ToList());

            if (batches.Count == 0)
                return;
            DoMenthodByDispatcher(() =>
            {
                Batchlist = batches;
                CurrentBatch = Batchlist[0];
            });

            var hourGroups = batches.Select(x => new
            {
                Element = x,
                Day = ((DateTime)x.insert_time).Date,
                Hour = ((DateTime)x.insert_time).Hour,

            }).GroupBy(x => new { x.Day, x.Hour }).Select(x => new BatchSumItem
            {
                Date = new DateTime(x.Key.Day.Year, x.Key.Day.Month, x.Key.Day.Day, x.Key.Hour, 0, 0),
                Excellent = x.Where(e => e.Element.grade == "优秀").Count(),
                Good = x.Where(g => g.Element.grade == "良好").Count(),
                Poor = x.Where(p => p.Element.grade == "较差").Count()
            });
            DoMenthodByDispatcher(() =>
            {
                BatchSumList = new ObservableCollection<BatchSumItem>(hourGroups);
            });


        }

        public BaseCommand ConfigCommand { get => new BaseCommand(ConfigCommand_Executed); }
        public void ConfigCommand_Executed(object obj)
        {
            new VM_WindowGradeConfig().ShowDialog();
        }

        public BaseCommand AddCusotmIdCommand { get => new BaseCommand(AddCusotmIdCommand_Executed); }
        public void AddCusotmIdCommand_Executed(object obj)
        {

            batch modifiedbatch;
            if (obj != null)
                modifiedbatch = obj as batch;
            else
                modifiedbatch = JsonConvert.DeserializeObject<batch>(JsonConvert.SerializeObject(CurrentBatch));
            var dlg = new VM_WindowTextBoxDlg("请输入批次号");
            dlg.ShowDialog();
            if ((dlg.UIElement as Window).DialogResult != true)
                return;
            modifiedbatch.user_custom_id = dlg.Text;

            surfaceEntities.batch.AddOrUpdate(modifiedbatch);
            if (surfaceEntities.SaveChanges() != 1)
            {
                MessageBox("保存失败");
                Logger.Info($"批次{modifiedbatch.main_id}的用户定义批次号{modifiedbatch.user_custom_id}保存失败");
            }
            //if (CurrentBatch.main_id == modifiedbatch.main_id)
            //{
            //    CurrentBatch.user_custom_id = modifiedbatch.user_custom_id;
            //}
        }

        //定义两个变量，分别存储选中的钢材缺陷和图像缺陷，用于删除操作
        public ObservableCollection<steel_defect> SelectedSteelDefects { get; set; }
        public ObservableCollection<Imagedefectinfo> SelectedImageDefects { get; set; }

        public BaseCommand DeleteSteelDefectCommand
        {
            get => new BaseCommand((obj) =>
            {
                var defects = SelectedSteelDefects;
                if (defects.Any())
                {
                    var all_image_defect_ids = defects.Select(t => new { ids = t.image_defect_ids_text.Split() }).SelectMany(s => s.ids).ToArray();
                    eshelper.BulkDeleteDefects(all_image_defect_ids);
                    foreach (var steel_Defects in SteelDefects)
                    {
                        foreach (var steel_defect in steel_Defects.ToArray())
                        {
                            if (defects.Contains(steel_defect))
                                steel_Defects.Remove(steel_defect);
                        }
                    }
                    foreach (var steel_defect in ShownSteelDefects.ToArray())
                    {
                        if (defects.Contains(steel_defect))
                            ShownSteelDefects.Remove(steel_defect);
                    }
                }

            });
        }

        public BaseCommand DeleteDefectCommand
        {
            get => new BaseCommand((obj) =>
            {
                var select_defects = SelectedImageDefects;
                if (select_defects.Any())
                {
                    eshelper.BulkDeleteDefects(select_defects.Select(d => d.CurrentDefect.id).ToArray());
                    foreach (var image_defect in ImageDefectlist.ToArray())
                    {
                        if (select_defects.Contains(image_defect))
                            ImageDefectlist.Remove(image_defect);
                    }
                }

            });
        }
        #region 修改缺陷
        public BaseCommand ModifyDefectCommand
        {
            get => new BaseCommand((obj) =>
            {
                var select_defects = SelectedImageDefects;
                if (select_defects.Any())
                {
                    RequestShowDialog?.Invoke(this, new ShowDialogEventArgs((type) =>
                    {
                        eshelper.BulkUpdateDefectType(type, select_defects.Select(d => d.CurrentDefect.id).ToArray());
                        foreach (var image_defect in select_defects)
                        {
                            image_defect.CurrentDefect.type = type;
                        }

                    }));
                }

            });
        }
        public delegate void DialogCallback(int result);
        public event EventHandler<ShowDialogEventArgs> RequestShowDialog;

        public class ShowDialogEventArgs : EventArgs
        {
            // 定义一个回调委托
            public DialogCallback Callback { get; private set; }

            public ShowDialogEventArgs(DialogCallback callback)
            {
                Callback = callback;
            }
        }
        #endregion

        public BaseCommand ReEvaluateCommand
        {
            get => new BaseCommand((obj) =>
            {

                Task.Run(async () =>
                {
                    HttpClient client = new HttpClient() { Timeout = TimeSpan.FromSeconds(3) };
                    var url = ConfigHelper.GetConfig("detect_url");
                    var cancellationTokenSource = new CancellationTokenSource();
                    var response = new HttpResponseMessage();
                    try
                    {
                        response = await client.PostAsync(url, new StringContent(JsonConvert.SerializeObject(new { main_id = CurrentBatch.main_id, signal = 2 }), Encoding.UTF8), cancellationTokenSource.Token);
                    }
                    catch (OperationCanceledException)
                    {
                        if (StaticData.DataBase == DataFrom.Test)
                        {
                            response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
                        }
                    }
                    if (response.IsSuccessStatusCode)
                    {
                        //string result = await response.Content.ReadAsStringAsync();
                        DoMenthodByDispatcher(() =>
                        {
                            CurrentBatch.finished = false;
                            var batch=surfaceEntities.batch.Where(t=>t.main_id==CurrentBatch.main_id).FirstOrDefault();
                            batch.finished = false;
                            surfaceEntities.Entry(batch).State = EntityState.Modified;
                            var count = surfaceEntities.SaveChanges();
                            if (count != 1)
                            {
                                Logger.Warn($"mysql保存{CurrentBatch.main_id}批次的finished修改失败");

                            }
                        });
                    }
                    else
                    {
                        MessageBox("发送消息失败");
                    }
                });



            });
        }
        public BaseCommand ReviewDefectCommand
        {
            get => new BaseCommand((obj) =>
            {

            });
        }


        
        public ObservableCollection<T> AfterAddRange<T>(ObservableCollection<T> orgianRange, ObservableCollection<T> addedRange)
        {
            var list = orgianRange.ToList();
            list.AddRange(addedRange);
            return new ObservableCollection<T>(list);
        }

        internal void GotoHistoryDefect(string main_id, string steeldefect_id)
        {
            var batch = surfaceEntities.batch.AsNoTracking().Where(t => t.main_id == main_id).FirstOrDefault();
            if (batch == null)
            {
                MessageBox("未找到该批次");
            }
            else
            {
                gotoSteelDefectID = steeldefect_id;
                CurrentBatch = batch;
                VM_WindowMain.GetInstance().ChangeMainFrameCommand.Execute("history");
            }

        }
    }
    public class BatchSumItem
    {
        public DateTime Date { get; set; }
        public int Excellent { get; set; }
        public int Good { get; set; }
        public int Poor { get; set; }

    }

    class AlertTypeComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            Dictionary<string, int> dict = new Dictionary<string, int>
            {
                { "疑似", 1 },
                { "警告", 2 },
                { "报警", 3 }
            };
            // 自定义排序规则，这里是按照字符串长度进行排序
            return dict[x].CompareTo(dict[y]);
        }
    }



}
